package gis.toolkit;

import gis.algorithm.BresenhamLine;
import gis.algorithm.Extent;
import gis.algorithm.GeoPoint;
import gis.algorithm.RqLineGrid;
import gis.algorithm.grid.GridUtils;
import gis.algorithm.grid.RqGridMap;
import gis.common.GisConfig;
import gis.core.bean.KeyValue;
import gis.core.bean.ResValue;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.math.util.MathUtils;

import java.awt.*;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Xiaobing on 2017/3/29.
 */
public class GaoTieHelper {

    private String basePath = this.getClass().getResource("/").getPath();


    public static void main(String[] args) {
        GaoTieHelper helper = new GaoTieHelper();
        helper.LineToGridForBeijing();

    }

    public List<ResValue> getHighSpeedRailAllPoints() {
        //List<ResValue> list = loadLine();
        List<ResValue> list = loadStationPoint();
        return list;
    }

    public List<RqGridMap> getHighSpeedRailLineGrid() {
        List<ResValue> ls = loadLine();
        List<RqGridMap> rqs = getRqGrid(ls);

        return rqs;
    }

    public List<RqLineGrid> getHighSpeedRailLineGridTemp() {
        List<ResValue> list = loadLine();
        List<RqLineGrid> grids = new ArrayList<>();
        ResValue p0 = null;
        ResValue p1 = null;
        for (int i = 0; i < list.size(); i++) {
            if (p0 == null) {
                p0 = list.get(i);
            } else {
                p1 = list.get(i);
                try {
                    if (i == 61) {
                        double a = 0;
                    }
                    List<RqLineGrid> temp = BresenhamLine.LineToGrid(p0.getLongitude(), p1.getLongitude(), p0.getLatitude(), p1.getLatitude());
                    grids.addAll(temp);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                p0 = p1;
            }
        }

        List<ResValue> stations = loadStationPoint();
        ResValue current = stations.get(0);
        ResValue next = stations.get(1);
        int flag = 2;
        int maxflag = stations.size();
        Map<String, ResValue> map = getStationIdMap(next);
        String nextId = getID(next.getLongitude(), next.getLatitude(), 0.0005);

        for (int i = 0; i < grids.size(); i++) {
            RqLineGrid grid = grids.get(i);
            grid.setIndex(i);
            grid.setStationToStationId(current.getId());
            grid.setStationToStationName(current.getName());
            if (map.containsKey(grid.getId())) {
                current = next;
                if (flag < maxflag) {
                    next = stations.get(flag);
                }
                map = getStationIdMap(next);
                flag++;
            }
        }

        writeGridFile(grids);
        writeExpandGrid(grids);
        return grids;
    }

    public List<RqLineGrid> getHighSpeedRailLineGridExTemp() {
        List<RqLineGrid> grids = getHighSpeedRailLineGridTemp();
        List<RqLineGrid> list = new ArrayList<>();
        int i = 0;
        for (RqLineGrid grid : grids) {
            expandGrid(grid, list);
            i++;
            if (i > 500) {
                break;
            }
        }
        return list;
    }

    private List<RqGridMap> getRqGrid(List<ResValue> list) {
        List<RqGridMap> rqs = new ArrayList<>();
        ResValue p0 = null;
        ResValue p1 = null;
        List<GeoPoint> all = new ArrayList<>();
        List<GeoPoint> ps = null;
        for (int i = 0; i < list.size(); i++) {
            if (i == 0) {
                p0 = list.get(0);
            } else {
                p1 = list.get(i);
                ps = BresenhamLine.Line2Points(p0.getLongitude(), p1.getLongitude(), p0.getLatitude(), p1.getLatitude(), 0.0005);
                all.addAll(ps);
            }
        }

        RqGridMap rq = null;
        for (int i = 0; i < all.size(); i++) {
            GeoPoint gp = all.get(i);
            rq = new RqGridMap();
            rq.setExtent(new Extent(gp.getX(), gp.getX() + 0.0005, gp.getY(), gp.getY() + 0.0005));
            rqs.add(rq);
        }


        return rqs;
    }

    private Map<String, ResValue> getStationIdMap(ResValue r) {
        Map<String, ResValue> map = new HashMap<>();
        String nextId = getID(r.getLongitude(), r.getLatitude(), 0.0005);
        map.put(nextId, r);

        int i = 1;
        nextId = getID(r.getLongitude() + (i * 0.0005), r.getLatitude(), 0.0005);
        map.put(nextId, r);

        nextId = getID(r.getLongitude() - (i * 0.0005), r.getLatitude(), 0.0005);
        map.put(nextId, r);

        nextId = getID(r.getLongitude(), r.getLatitude() - 0.0005, 0.0005);
        map.put(nextId, r);
        nextId = getID(r.getLongitude(), r.getLatitude() + 0.0005, 0.0005);
        map.put(nextId, r);

        nextId = getID(r.getLongitude() - 0.0005, r.getLatitude() - 0.0005, 0.0005);
        map.put(nextId, r);
        nextId = getID(r.getLongitude() + 0.0005, r.getLatitude() + 0.0005, 0.0005);
        map.put(nextId, r);
        nextId = getID(r.getLongitude() + 0.0005, r.getLatitude() - 0.0005, 0.0005);
        map.put(nextId, r);
        nextId = getID(r.getLongitude() - 0.0005, r.getLatitude() + 0.0005, 0.0005);
        map.put(nextId, r);

        return map;
    }

    /**
     * 根据经纬度 生成ID
     *
     * @param x
     * @param y
     * @return
     */
    private String getID(Double x, Double y, double decimal) {
        String id = "";
        int length = StringUtils.splitPreserveAllTokens(decimal + "", ".")[1].length();
        String[] xtemp = StringUtils.splitPreserveAllTokens(x.toString(), ".");
        String dec = StringUtils.rightPad(xtemp[1], length, '0');
        int last = Integer.parseInt(dec.substring(length - 1, length));
        if (last >= 0 && last < 5) {
            id = xtemp[0] + dec.substring(0, length - 1) + "0";
        } else {
            id = xtemp[0] + dec.substring(0, length - 1) + "5";
        }
        // y
        String[] ytemp = StringUtils.splitPreserveAllTokens(y.toString(), ".");
        dec = StringUtils.rightPad(ytemp[1], length, '0');
        last = Integer.parseInt(dec.substring(length - 1, length));
        if (last >= 0 && last < 5) {
            id += ytemp[0] + dec.substring(0, length - 1) + "0";
        } else {
            id += ytemp[0] + dec.substring(0, length - 1) + "5";
        }
        return id;
    }

    private List<ResValue> loadLine() {
        List<ResValue> list = new ArrayList<>();
        ResValue p = null;
        String path = GisConfig.GetInstance().getBasePath() + "config/sxgt_daxi.csv";
        InputStreamReader stream = null;
        BufferedReader reader = null;
        String line = "";
        try {
            stream = new InputStreamReader(new FileInputStream(path), "UTF-8");
            reader = new BufferedReader(stream);
            int i = 0;
            while ((line = reader.readLine()) != null) {
                String[] xy = StringUtils.splitPreserveAllTokens(line, ",");
                p = new ResValue();
                p.setTag(Integer.parseInt(xy[0]));
                p.setLongitude(Double.parseDouble(xy[1]));
                p.setLatitude(Double.parseDouble(xy[2]));

                i++;
                list.add(p);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    private List<ResValue> loadStationPoint() {
        List<ResValue> list = new ArrayList<>();
        ResValue p = null;
        String path = GisConfig.GetInstance().getBasePath() + "config/sx-gccz-latlon.txt";
        InputStreamReader stream = null;
        BufferedReader reader = null;
        String line = "";
        try {
            stream = new InputStreamReader(new FileInputStream(path), "UTF-8");
            reader = new BufferedReader(stream);
            int i = 0;
            while ((line = reader.readLine()) != null) {
                String[] c = StringUtils.splitPreserveAllTokens(line, ",");
                p = new ResValue();
                p.setTag(Integer.parseInt(c[0]));
                p.setLongitude(Double.parseDouble(c[2]));
                p.setLatitude(Double.parseDouble(c[3]));
                p.setName(c[4]);
                p.setId(c[5]);
                list.add(p);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    private void writeGridFile(List<RqLineGrid> grids) {
        String filePath = basePath + "config/bj-gt-jh-js-new.txt";
        int f = 0;
        File file = new File(filePath);

        FileOutputStream out = null;
        OutputStreamWriter osw = null;
        BufferedWriter bw = null;
        StringBuffer sb = new StringBuffer();
        try {
            out = new FileOutputStream(file);
            osw = new OutputStreamWriter(out, "UTF-8");
            bw = new BufferedWriter(osw);
            //标题
            sb.append("lineId|id|index|xmax|ymax|xmin|ymin|startpointx|startpointy|endpointx|endpointy|stationToStationId|stationToStationName\n");
            for (f = 0; f < grids.size(); f++) {
                RqLineGrid grid = grids.get(f);
                sb.append(grid.getLineId() + "|" + grid.getId() + "|" + grid.getIndex() + "|" + grid.getExtent().getxMax() + "|" + grid.getExtent().getyMax() + "|" + grid.getExtent().getxMin() + "|" + grid.getExtent().getyMin());
                sb.append("|" + grid.getStartPoint().getX() + "|" + grid.getStartPoint().getY() + "|" + grid.getEndPoint().getX() + "|" + grid.getEndPoint().getY() + "|" + grid.getStationToStationId() + "|" + grid.getStationToStationName() + "\n");
                if (f % 500 == 0) {
                    bw.write(sb.toString());
                    bw.flush();
                    sb = new StringBuffer();
                }
            }

            if (sb.length() > 0) {
                bw.write(sb.toString());
                bw.flush();
                sb = new StringBuffer();
            }
            bw.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("共生成：" + f + "铁路进过的栅格!");
        System.out.println("生成文件完成!");

    }

    private void writeExpandGrid(List<RqLineGrid> grids) {

        List<RqLineGrid> list = new ArrayList<>();
        for (RqLineGrid grid : grids) {
            expandGrid(grid, list);
        }

        String filePath = basePath + "config/bj-gt-jh-js-expend-new-5.txt";
        int f = 0;
        File file = new File(filePath);

        FileOutputStream out = null;
        OutputStreamWriter osw = null;
        BufferedWriter bw = null;
        StringBuffer sb = new StringBuffer();
        try {
            out = new FileOutputStream(file);
            osw = new OutputStreamWriter(out, "UTF-8");
            bw = new BufferedWriter(osw);
            //标题
            sb.append("lineId|id|index|xmax|ymax|xmin|ymin|stationToStationId|stationToStationName\n");
            for (f = 0; f < list.size(); f++) {
                RqLineGrid grid = list.get(f);
                sb.append(grid.getLineId() + "|" + grid.getId() + "|" + grid.getIndex() + "|" + grid.getExtent().getxMax() + "|" + grid.getExtent().getyMax() + "|" + grid.getExtent().getxMin() + "|" + grid.getExtent().getyMin());
                sb.append("|" + grid.getStationToStationId() + "|" + grid.getStationToStationName() + "\n");
                if (f % 500 == 0) {
                    bw.write(sb.toString());
                    bw.flush();
                    sb = new StringBuffer();
                }
            }

            if (sb.length() > 0) {
                bw.write(sb.toString());
                bw.flush();
                sb = new StringBuffer();
            }
            bw.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("共生成：" + f + "铁路进过的扩展栅格!");
        System.out.println("生成文件完成!");
    }

    public void expandGrid(RqLineGrid grid, List<RqLineGrid> list) {
        list.add(grid);
        Extent e = grid.getExtent();
        //List<Point> points = GridUtils.expandGridInt(e, 0.0005);
        //List<GeoPoint> points = GridUtils.expandGrid(e, 0.0005);
        List<GeoPoint> points = GridUtils.expandGrid5(e.getxMin(), e.getyMin(), 0.0005);
        for (GeoPoint p : points) {
            RqLineGrid temp = new RqLineGrid();
            //temp.setId(StringUtils.replace(p.x + "", ".", "") + StringUtils.replace(p.y + "", ".", ""));
            //temp.setId(GridUtils.getGridID(p.getX(), p.getY()));
            temp.setLineId(grid.getLineId());
            temp.setIndex(grid.getIndex());
            temp.setStationToStationId(grid.getStationToStationId());
            temp.setStationToStationName(grid.getStationToStationName());
            //Extent extent = new Extent();
            //extent.setxMin(p.x * 1.0 / 10000);
            //extent.setyMin(p.y * 1.0 / 10000);
            //extent.setxMax((p.x * 1.0 + 5) / 10000);
            //extent.setyMax((p.y * 1.0 + 5) / 10000);
            //temp.setExtent(extent);
            //temp.setExtent(new Extent(p.getX(), p.getX() + 0.0005, p.getY(), p.getY() + 0.0005));
            //修正数据
            Extent extent = new Extent();
            extent.setxMin(MathUtils.round(p.getX() + 0.00000000001, 4));
            extent.setxMax(MathUtils.round(p.getX() + 0.0005 + 0.00000000001, 4));
            extent.setyMin(MathUtils.round(p.getY() + 0.00000000001, 4));
            extent.setyMax(MathUtils.round(p.getY() + 0.0005 + 0.00000000001, 4));
            temp.setExtent(extent);

            temp.setId(GridUtils.getGridID(extent.getxMin(), extent.getyMin(), 0.0005));
            list.add(temp);
        }

        String a = "";
    }

    public List<RqLineGrid> loadTestGrid() {
        List<RqLineGrid> list = new ArrayList<>();
        String path = GisConfig.GetInstance().getBasePath() + "config/sx-gt-ty-xa.txt";
        InputStreamReader stream = null;
        BufferedReader reader = null;
        String line = "";
        RqLineGrid p = null;
        int xmin = 0;
        int ymin = 0;

        try {
            stream = new InputStreamReader(new FileInputStream(path), "UTF-8");
            reader = new BufferedReader(stream);
            int i = 0;
            while ((line = reader.readLine()) != null) {
                if (i == 0) {
                    i++;
                    continue;
                }
                i++;
                String[] c = StringUtils.splitPreserveAllTokens(line, "|");
                p = new RqLineGrid();
                p.setStartPoint(new GeoPoint(Double.parseDouble(c[7]), Double.parseDouble(c[8])));
                p.setEndPoint(new GeoPoint(Double.parseDouble(c[9]), Double.parseDouble(c[10])));
                p.setStationToStationId(c[11]);
                p.setStationToStationName(c[12]);
                p.setIndex(Integer.parseInt(c[2]));

                xmin = (int) Math.floor((Double.parseDouble(c[5]) + 0.0000001) * 10000);
                ymin = (int) Math.floor((Double.parseDouble(c[6]) + 0.0000001) * 10000);

                p.setId(StringUtils.replace(xmin + "", ".", "") + StringUtils.replace(ymin + "", ".", ""));
                Extent e = new Extent();
                e.setxMin(xmin * 1.0 / 10000);
                e.setyMin(ymin * 1.0 / 10000);
                e.setxMax((xmin * 1.0 + 5) / 10000);
                e.setyMax((ymin * 1.0 + 5) / 10000);
                p.setExtent(e);
                //p.setExtent(new Extent(Double.parseDouble(c[5]), Double.parseDouble(c[3]), Double.parseDouble(c[6]), Double.parseDouble(c[4])));

                list.add(p);

            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        //写入铁路栅格
        writeGridFile(list);
        writeExpandGrid(list);
        return list;
    }

    /**
     * 通用线路栅格化  输出到文件中
     *
     * @return
     */
    public List<RqLineGrid> lineToGrid(List<ResValue> list) {
        List<RqLineGrid> grids = new ArrayList<>();
        ResValue p0 = null;
        ResValue p1 = null;
        for (int i = 0; i < list.size(); i++) {
            if (p0 == null) {
                p0 = list.get(i);
            } else {
                p1 = list.get(i);
                try {
                    if (i == 61) {
                        double a = 0;
                    }
                    List<RqLineGrid> temp = BresenhamLine.LineToGrid(p0.getLongitude(), p1.getLongitude(), p0.getLatitude(), p1.getLatitude());
                    grids.addAll(temp);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                p0 = p1;
            }
        }

        for (int i = 0; i < grids.size(); i++) {
            RqLineGrid grid = grids.get(i);
            grid.setIndex(i);
        }


        //writeGridFile(grids);
        //writeExpandGrid(grids);
        return grids;
    }

    /**
     * 读取北京电信
     *
     * @return
     */
    private List<KeyValue> loadLine_beijing_dianxing() {
        List<KeyValue> r = new ArrayList<>();

        ResValue p = null;
        String path = basePath + "config/bj_jinghu_gaotie.txt";
        InputStreamReader stream = null;
        BufferedReader reader = null;
        String line = "";
        try {
            stream = new InputStreamReader(new FileInputStream(path), "UTF-8");
            reader = new BufferedReader(stream);
            int i = 0;
            while ((line = reader.readLine()) != null) {
                String[] t = StringUtils.splitPreserveAllTokens(line, "|");
                KeyValue kv = new KeyValue();
                kv.setId(i + "");
                kv.setName(t[0]);
                List<ResValue> list = new ArrayList<>();
                String[] xys = StringUtils.splitPreserveAllTokens(t[1], ";");
                for (String s : xys) {
                    if (StringUtils.isEmpty(s)) continue;
                    String[] xy = StringUtils.splitPreserveAllTokens(s, ",");
                    if (xy.length < 2) continue;

                    p = new ResValue();
                    p.setLongitude(Double.parseDouble(xy[0]));
                    p.setLatitude(Double.parseDouble(xy[1]));
                    list.add(p);
                }
                kv.setTag(list);

                r.add(kv);
                i++;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return r;
    }

    public void LineToGridForBeijing() {
        List<KeyValue> ret = new ArrayList<>();

        List<RqLineGrid> grids = getLineToGridN();

        //writeGridFile(grids);
        writeExpandGrid(grids);

    }

    public List<GeoPoint> getLine2Points() {
        List<GeoPoint> points = new ArrayList<>();
        List<KeyValue> lines = loadLine_beijing_dianxing();
        for (KeyValue line : lines) {
            List<ResValue> line_points = (List<ResValue>) line.getTag();
            ResValue p0 = null;
            int i = 0;
            for (ResValue rs : line_points) {
                if (p0 != null) {
                    List<GeoPoint> ps = BresenhamLine.Line2Points(p0.getLongitude(), rs.getLongitude(), p0.getLatitude(), rs.getLatitude(), 0.0005);
                    points.addAll(ps);
                }
                p0 = rs;
            }
        }
        return points;
    }

    public List<RqLineGrid> getLineToGridN() {
        List<RqLineGrid> points = new ArrayList<>();
        List<KeyValue> lines = loadLine_beijing_dianxing();
        for (KeyValue line : lines) {
            List<ResValue> line_points = (List<ResValue>) line.getTag();
            ResValue p0 = null;
            int i = 0;
            for (ResValue rs : line_points) {
                if (p0 != null) {
                    List<RqLineGrid> ps = BresenhamLine.LineToGrid(p0.getLongitude(), rs.getLongitude(), p0.getLatitude(), rs.getLatitude());
                    for (RqLineGrid p : ps) {
                        p.setLineId("0");
                        p.setIndex(i);
                        p.setStationToStationId(line.getId());
                        p.setStationToStationName(line.getName());

                        //修正数据
                        Extent extent = p.getExtent();
                        extent.setxMin(MathUtils.round(extent.getxMin() + 0.00000000001, 4));
                        extent.setxMax(MathUtils.round(extent.getxMax() + 0.00000000001, 4));
                        extent.setyMin(MathUtils.round(extent.getyMin() + 0.00000000001, 4));
                        extent.setyMax(MathUtils.round(extent.getyMax() + 0.00000000001, 4));
                        p.setId(GridUtils.getGridID(extent.getxMin(), extent.getyMin(), 0.0005));
                        i++;
                    }
                    points.addAll(ps);
                }
                p0 = rs;
            }
        }
        return points;
    }
}